package gagak.framework.web.paramresovler.requestresponse;

import gagak.framework.web.param.MethodParameter;
import gagak.framework.web.paramresovler.HandlerMethodArgumentResolver;
import gagak.framework.web.support.request.NativeWebRequest;

import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

/*
 * @program: ce
 * @description:
 * @author: houhong
 * @create: 2022-11-25 21:57
 */
public class ServletResponseMethodArgumentResolver implements HandlerMethodArgumentResolver {


    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Class<?> paramType = parameter.getParameterType();
        return (ServletResponse.class.isAssignableFrom(paramType) ||
                OutputStream.class.isAssignableFrom(paramType) ||
                Writer.class.isAssignableFrom(paramType));
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  NativeWebRequest webRequest) throws Exception {


        Class<?> paramType = parameter.getParameterType();

        // ServletResponse, HttpServletResponse
        if (ServletResponse.class.isAssignableFrom(paramType)) {
            return resolveNativeResponse(webRequest, paramType);
        }

        return resolveArgument(paramType, resolveNativeResponse(webRequest, ServletResponse.class));
    }

    private <T> T resolveNativeResponse(NativeWebRequest webRequest, Class<T> requiredType) {
        T nativeResponse = webRequest.getNativeResponse(requiredType);
        if (nativeResponse == null) {
            throw new IllegalStateException(
                    "Current response is not of type [" + requiredType.getName() + "]: " + webRequest);
        }
        return nativeResponse;
    }

    private Object resolveArgument(Class<?> paramType, ServletResponse response) throws IOException {
        if (OutputStream.class.isAssignableFrom(paramType)) {
            return response.getOutputStream();
        }
        else if (Writer.class.isAssignableFrom(paramType)) {
            return response.getWriter();
        }

        // Should never happen...
        throw new UnsupportedOperationException("Unknown parameter type: " + paramType);
    }
}